#include <iostream>
#include <sstream>
#include "Library_t.h"
#include "Book_t.h"
#include "Borrower_t.h"

// validates that the user has entered numeric value
template<class T>
void getNum(T& num);

int main(int argc, char* argv[])
{
	//if(0)
	//{	
	//	int res;	
	//	Book_t *b1 = new Book_t("C++ for dummies","Someone",1,1);
	//	Book_t *b2 = new Book_t("Advanced C++","Someone Smart",2); //by default- only one copy
	//	Book_t *b3 = new Book_t("Yellow Pages","BEZEQ",100100,50);
	//	Book_t *notInLib = new Book_t("Winnie-the-Pooh","A. A. Milne",50,10);

	//	Borrower_t *r1 = new Borrower_t("Alex");
	//	Borrower_t *r2 = new Borrower_t("Rinat");
	//	Borrower_t *r3 = new Borrower_t("Eyal");

	//	Library_t lib;

	//	lib.addBook(b1);
	//	if(!lib.addBook(b1))
	//		std::cout<<"Book (ISBN "<<b1->isbn()<<") already exists in library!" << std::endl;
	//
	//	lib.addBook(b2);
	//	lib.addBook(b3);

	//	res=lib.addBorrower(r1);
	//	std::cout<<"Borrower has ID="<<res <<std::endl;
	//	if(!lib.addBorrower(r1))
	//		std::cout<<"Borrower (ID "<<r1->id()<<") already exists in library!" << std::endl;
	//
	//	res=lib.addBorrower(r2);
	//	std::cout<<"Borrower has ID="<<res <<std::endl;
	//	res=lib.addBorrower(r3);
	//	std::cout<<"Borrower has ID="<<res <<std::endl;

	//	res=lib.borrow(r1,b2);

	//	res=lib.removeBook(b2); // cannot be removed

	//	res=lib.borrow(r2,b2); // r2 now on waiting list
	//	//std::cout<<"res="<<res<<std::endl;
	//	//std::cout << *b2;

	//	res=lib.borrow(r3,b2); // r3 now on waiting list
	//	res=lib.borrow(r3,b3);


	//	res=lib.returnBook(r1,b2); // r2 should get the book, r3 still on waiting list
	//	//std::cout<<"res="<<res<<std::endl;
	//	//std::cout << *b2;

	//	std::cout << lib.bookReport();
	//	std::cout << lib.borrowerReport() << std::endl;

	//	res=lib.returnBook(r2,b2); // r3 should get the book
	//	//std::cout<<"res="<<res<<std::endl;
	//	//std::cout << *b2;
	//
	//	std::cout << lib.bookReport();

	//	res=lib.borrow(r2,b2); // r2 should be added to waiting list
	//	res=lib.borrow(r2,b2); // r2 should already be on waiting list, so do nothing
	//	res=lib.borrow(r2,b2); // "-"
	//
	//	std::cout << lib.borrowerReport() << std::endl;

	//	lib.returnBook(r2,b2);
	//	lib.returnBook(r3,b3);
	//	lib.returnBook(r3,b2);
	//	lib.returnBook(r2,b2);

	//	lib.borrow(r1,notInLib);


	//	std::cout << lib.bookReport();

	//	delete notInLib;
	//	getchar();
	//}

	if(1)
	{
		Library_t lib;

		Book_t *b1 = new Book_t("C++ for dummies","Someone",1,3);
		Book_t *b2 = new Book_t("Advanced C++","Someone Smart",2); //by default- only one copy
		Book_t *b3 = new Book_t("Yellow Pages","BEZEQ",100100,50);
		Borrower_t *r1 = new Borrower_t("Alex");
		Borrower_t *r2 = new Borrower_t("Rinat");
		Borrower_t *r3 = new Borrower_t("Eyal");
		lib.addBook(b1); lib.addBook(b2); lib.addBook(b3);
		lib.addBorrower(r1); lib.addBorrower(r2); lib.addBorrower(r3);
		
		int cmd = -1;
		while(cmd != 0)
		{
			std::cout << "Please choose:" << std::endl;
			std::cout << "\t(1) Create and insert new borrower to the library" << std::endl;
			std::cout << "\t(2) Create and insert new book to the library" << std::endl;
			std::cout << "\t(3) Borrow a book" << std::endl;
			std::cout << "\t(4) Return a book" << std::endl;
			std::cout << "\t(5) Find user by ID" << std::endl;
			std::cout << "\t(6) Find book by IBSN" << std::endl;
			std::cout << "\t(7) Remove a user from library" << std::endl;
			std::cout << "\t(8) Remove a book from library" << std::endl;
			std::cout << "\t(9) Print book report" << std::endl;
			std::cout << "\t(10) Print borrower report" << std::endl;
			std::cout << "\t(0) Exit" << std::endl;

			std::cin >> cmd;

			switch(cmd)
			{
				case 1: // new borrower
					{
						std::string name;
						std::cout << "Insert borrower's name: ";
						std::cin.ignore(1000,'\n');
						std::getline(std::cin, name);
						Borrower_t *b=new Borrower_t(name);
						unsigned long res=lib.addBorrower(b);
						if(res == 0)
							{
								std::cout << "--> This borrower is already in the library." << std::endl;
								delete b;
							}
						else
							std::cout << std::endl << name <<"'s ID=" << res << std::endl;
						break;
					}
				case 2: //new book
					{
						std::cin.clear();
						std::cin.ignore(100,'\n');
						std::string name, author;
						ull isbn;
						size_t copies;
						std::cout << "Insert book name: ";
						std::getline(std::cin, name);


						std::cout << "Insert book's author name: " ;
						std::getline(std::cin, author);

						std::cout << "Insert book's ISBN: ";
						getNum(isbn);

						std::cout << "Insert number of available copies: ";
						getNum(copies);

						if(isbn == 0 || copies == 0)
						{
							std::cout << " --> ISBN=0 or Copies=0 are invalid values.";
							break;
						}

						Book_t *b=new Book_t(name,author,isbn,copies);
						bool res=lib.addBook(b);
						if(!res)
							{
								std::cout << std::endl << "--> This book is already in the library." << std::endl;
								delete b;
							}
						else
							std::cout << std::endl << "--> Book added." << std::endl;
						break;
					}
				case 3: // borrow
					{
						ull isbn;
						unsigned long id;

						std::cin.clear();
						std::cin.ignore();
						std::cout << "Insert borrower ID: ";
						getNum(id);
						std::cout << "Enter book ISBN: ";
						getNum(isbn);

						Book_t* book = lib.findBook(isbn);
						Borrower_t* borrower = lib.findBorrower(id);

						if(borrower!=NULL && book!=NULL)
						{
							int res=lib.borrow(borrower,book);
							if(res==1)
							{
								std::cout << "--> Successfully borrwed!" << std::endl << std::endl;
							}
							else if(res==0)
								std::cout << "--> Borrower added to waiting list." << std::endl << std::endl;
							else
								std::cout <<"--> This book is already borrowed by the borrower" << std::endl << std::endl;
						}
						else
							std::cout << "--> Book ISBN or borrower ID are not valid."  << std::endl << std::endl;

						break;
					}

				case 4: // return book
					{
						ull isbn;
						unsigned long id;
						std::cin.clear();
						std::cin.ignore();

						std::cout << "Insert borrower ID: ";
						getNum(id);
						std::cout << "Enter book ISBN: ";
						getNum(isbn);

						Book_t* book = lib.findBook(isbn);
						Borrower_t* borrower = lib.findBorrower(id);

						if(book!=NULL && borrower!=NULL)
						{
							int res=lib.returnBook(borrower, book);
							if(res==1)
								std::cout << "--> Book returned!" << std::endl << std::endl;
							else if(res==0)
								std::cout << "--> Book returned, and borrowed to a waiting user." << std::endl << std::endl;
							else
								std::cout << "--> This book is not borrwed by this borrower." << std::endl << std::endl;
						}
						else
							std::cout << "--> Book or borrower are invalid" << std::endl << std::endl;

						
						break;
					}
				case 5: // find user
					{
						unsigned long id;
						std::cin.clear();
						std::cin.ignore();

						std::cout << "Enter user ID: ";
						getNum(id);
						
						Borrower_t* borrower = lib.findBorrower(id);
						if(borrower!=NULL)
							std::cout << "--> Borrower found: " << borrower->name() << std::endl << std::endl;
						else
							std::cout << "--> Borrower not found." << std::endl << std::endl;
						break;
					}
				case 6: // find book
					{
						ull isbn;
						std::cin.clear();
						std::cin.ignore();

						std::cout << "Enter book ISBN: ";
						getNum(isbn);
						
						Book_t* book = lib.findBook(isbn);
						if(book!=NULL)
							std::cout << "--> Book found: " << book->name() << std::endl << std::endl;
						else
							std::cout << "--> Book not found." << std::endl << std::endl;
						break;
					}
				case 7: // remove borrower
					{
						unsigned long id;
						std::cin.clear();
						std::cin.ignore();

						std::cout << "Enter user ID: ";
						getNum(id);
						Borrower_t* b = lib.findBorrower(id);
						if(b!=NULL)
						{
							if(lib.removeBorrower(b, true))
								std::cout << "--> Borrower removed" << std::endl << std::endl;
							else
								std::cout << "--> Can't remove borrower. Maybe he has borrowed books?" << std::endl << std::endl;
						}
						else
							std::cout << "--> User not found." << std::endl << std::endl;
						break;
					}
				case 8: // remove book
					{
						ull isbn;
						std::cin.clear();
						std::cin.ignore();

						std::cout << "Enter book ISBN: ";
						getNum(isbn);
						Book_t* book = lib.findBook(isbn);
						if(book!=NULL)
						{
							if(lib.removeBook(book, true))
								std::cout << "--> Book removed" << std::endl << std::endl;
							else
								std::cout << "--> Can't remove book. Maybe it is borrowed by someone?" << std::endl << std::endl;
						}
						else
							std::cout << "--> Invalid Book" << std::endl << std::endl;
						break;
					}
				case 9: // book report
					std::cout << lib.bookReport();
					break;
				case 10: // borrower report
					std::cout << lib.borrowerReport();
					break;
				case 0:
					break;
				default:
					break;
			}
		}

		
	}
	return 0;
}

template<class T>
void getNum(T& num)
{
	T tmpNum;
	std::cin.sync();
	std::cin >> tmpNum;
	while(!std::cin.good())
	{
		std::cout << "Please enter numbers only: ";
		std::cin.clear();
		std::cin.ignore(1000,'\n');
		std::cin >> tmpNum;
	}
	num = tmpNum;
}